/*
 *  CSMACAListener.cpp
 *  simulator
 *
 *  Created by  on 4/4/12.
 *  Copyright 2012 __MyCompanyName__. All rights reserved.
 *
 */

#include "CSMACAListener.hpp"
#include "Settings.hpp"

using namespace Sim ;



CSMACAListener :: CSMACAListener ( ID const & name )
:	StateMachineNode<CSMACAListener> ( name, waitForData )
{
	registerStateCallback ( waitForData , &CSMACAListener::update_waitForData , "Waiting for data to be received." ) ;
	registerStateCallback ( sendACK , &CSMACAListener::update_sendACK , "Sending acknowledgement." ) ;
	registerStateCallback ( waitConfirmACK , &CSMACAListener::update_waitConfirmACK , "Waiting acknowledgement received." ) ;

}

void	CSMACAListener :: update_waitCollision	( UInteger currentTime , Medium::MsgSet const & currentReception ){//Waits until packet collision is finished and times out
	if(createWaitCollision == currentTime){
		setState(waitForData);
	}
	else {
		setState(waitCollision);
	}
}

void	CSMACAListener :: update_waitForData	( UInteger currentTime , Medium::MsgSet const & currentReception ){
	int flag = 0;
	int dataPacketCount = 0;
	if(currentReception.size() != 0){
		std::list<Message*> current = currentReception;
		std::list<Message*>::iterator	here	=	current.begin() ;
		std::list<Message*>::iterator	end		=	current.end() ;
		while ( here != end )
		{
			Message & m = * (*(here++)) ;
			if(m.type == Message::kTypeData){//Counts data packets inflight
				dataPacketCount++;
			}
			if(dataPacketCount > 1){//If more than 1 data packet, then collision.
				createWaitCollision = Settings::shared().controlPacketDuration+ Settings::shared().SIFSDuration + Settings::shared().dataPacketDuration + currentTime;// Goes to state and waits specified time until initiator timeouts
				setState(waitCollision);
			}
			if(m.target == identity && m.lastSlot == currentTime && dataPacketCount == 1){//Message target was intended for identity and only 1 data packet in flight send ack.
				flag = 1;
				sender = m.sender;
				m.status = Message::kStatusSuccessful ;
				break;
			}
		}
		if(flag == 1){
			createSIFS = Settings::shared().SIFSDuration + currentTime;
			setState(sendACK);
		}
		else {
			setState(waitForData);
		}

	}
	else{
		setState(waitForData);
	}
}


void	CSMACAListener :: update_sendACK	( UInteger currentTime , Medium::MsgSet const & currentReception ){
	if(createSIFS == currentTime){
		message = new Message ( identity , sender , Message::kTypeACK , Settings::shared().controlPacketDuration) ;
		Medium::shared() . registerMessage ( message ) ;
		setState(waitConfirmACK);
	}
	else {
		setState(sendACK);
	}
}
void	CSMACAListener :: update_waitConfirmACK	( UInteger currentTime , Medium::MsgSet const & currentReception ){
   	if(message -> status == Message::kStatusSuccessful){
		message -> release();
		message = 0;
		setState(waitForData);
	}
	else {
		setState(waitConfirmACK);
	}

}

